﻿//
// © Algobox Ltd - Benn Eichhorn
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using Algobox.Objects.Finance.Assets.Stock;
using Algobox.Feeds.Finance.MarketData;

namespace Algobox.Feeds.Finance.Simulators
{
    public class RandomMarketSimulator : IMarketFeedAdaptor
    {
        public RandomMarketSimulator()
        {

        }

        const decimal DEFAULT_TICK = 0.05m;

        System.Threading.Timer _timer;
        Random _random;
        ConcurrentDictionary<IStock, int> _mapSecuritiesCount = new ConcurrentDictionary<IStock, int>();

        ConcurrentDictionary<IStock, List<IMarketUpdateAsk>> _mapAskRequests = new ConcurrentDictionary<IStock, List<IMarketUpdateAsk>>();
        ConcurrentDictionary<IStock, List<IMarketUpdateBid>> _mapBidRequests = new ConcurrentDictionary<IStock, List<IMarketUpdateBid>>();
        ConcurrentDictionary<IStock, List<IMarketUpdateLast>> _mapLastRequests = new ConcurrentDictionary<IStock, List<IMarketUpdateLast>>();
        ConcurrentDictionary<IStock, List<IMarketUpdatePhase>> _mapPhaseRequests = new ConcurrentDictionary<IStock, List<IMarketUpdatePhase>>();


        public event Action<IStock, long> OnSubscriptionAdded;
        public event Action<IStock, long> OnSubscriptionRemoved;
        public event Action OnMarketFeedShutdown;


        public string FeedName { get { return "MarketSimulator"; } }

        public bool IsStarted { get; set; }
        
        public bool Start()
        {
            _timer = new System.Threading.Timer(new System.Threading.TimerCallback(SendPrice));
            _random = new Random();
            return true;
        }

        public void Stop()
        {
            throw new NotImplementedException();
        }

        private void SendPrice(object a)
        {
            //double bid;
            //double ask;
        }

        private void InitialisePrices(IStock stock)
        {
            double price = _random.Next(100, 1000000) / 100;

            stock.Prices.Last.Price = price;
        }


        public void SubscribeBid(IStock stock, IMarketUpdateBid callback)
        {

            _mapBidRequests.AddOrUpdate(stock,
                    (security) =>
                    {
                        _mapSecuritiesCount.AddOrUpdate(stock,
                            (symbol) =>
                            {
                                return 1;
                            },
                            (symbol, count) =>
                            {
                                return count + 1;
                            });
                        return new List<IMarketUpdateBid>() { callback };
                    },
                    (key, list) =>
                    {
                        if (!list.Contains(callback))
                        {
                            _mapSecuritiesCount.AddOrUpdate(stock,
                               (symbol) =>
                               {
                                   return 1;
                               },
                               (symbol, count) =>
                               {
                                   return count + 1;
                               });
                            list.Add(callback);
                        }
                        else { } // don't subscribe twice you twat!
                        return list;
                    }
                );
        }

        public void SubscribeAsk(IStock stock, IMarketUpdateAsk callback)
        {
            _mapAskRequests.AddOrUpdate(stock,
                (security) =>
                {
                    _mapSecuritiesCount.AddOrUpdate(stock,
                        (symbol) =>
                        {
                            return 1;
                        },
                        (symbol, count) =>
                        {
                            return count + 1;
                        });
                    return new List<IMarketUpdateAsk>() { callback };
                },
                (key, list) =>
                {
                    if (!list.Contains(callback))
                    {
                        _mapSecuritiesCount.AddOrUpdate(stock,
                            (symbol) =>
                            {
                                return 1;
                            },
                            (symbol, count) =>
                            {
                                return count + 1;
                            });
                        list.Add(callback);
                    }
                    else { } // don't subscribe twice you twat!
                    return list;
                }
            );

        }

        public void SubscribeLast(IStock stock, IMarketUpdateLast callback)
        {
            _mapLastRequests.AddOrUpdate(stock,
                (security) =>
                {
                    _mapSecuritiesCount.AddOrUpdate(stock,
                        (symbol) =>
                        {
                            return 1;
                        },
                        (symbol, count) =>
                        {
                            return count + 1;
                        });
                    return new List<IMarketUpdateLast>() { callback };
                },
                (key, list) =>
                {
                    if (!list.Contains(callback))
                    {
                        _mapSecuritiesCount.AddOrUpdate(stock,
                            (symbol) =>
                            {
                                return 1;
                            },
                            (symbol, count) =>
                            {
                                return count + 1;
                            });
                        list.Add(callback);
                    }
                    else { } // don't subscribe twice you twat!
                    return list;
                }
            );
        }

        public void SubscribePhase(IStock stock, IMarketUpdatePhase callback)
        {
            _mapPhaseRequests.AddOrUpdate(stock,
                (security) =>
                {
                    _mapSecuritiesCount.AddOrUpdate(stock,
                                   (symbol) =>
                                   {
                                       return 1;
                                   },
                                   (symbol, count) =>
                                   {
                                       return count + 1;
                                   });
                    return new List<IMarketUpdatePhase>() { callback };
                },
                (key, list) =>
                {
                    if (!list.Contains(callback))
                    {
                        _mapSecuritiesCount.AddOrUpdate(stock,
                            (symbol) =>
                            {
                                return 1;
                            },
                            (symbol, count) =>
                            {
                                return count + 1;
                            });
                        list.Add(callback);
                    }
                    else { } // don't subscribe twice you twat!
                    return list;
                }
            );
        }

        public void UnsubscribeBid(IStock stock, IMarketUpdateBid callback)
        {
            _mapBidRequests.AddOrUpdate(stock,
                (security) =>
                {
                    // shouldn't ever really come in here
                    _mapSecuritiesCount.AddOrUpdate(stock,
                        (symbol) =>
                        {
                            return 0;
                        },
                        (symbol, count) =>
                        {
                            return count;
                        });
                    return new List<IMarketUpdateBid>();
                },
                (security, list) =>
                {
                    if (list.Contains(callback))
                    {
                        _mapSecuritiesCount.AddOrUpdate(stock,
                            (symbol) =>
                            {
                                return 0;
                            },
                            (symbol, count) =>
                            {
                                return --count;
                            });
                        list.Remove(callback);
                    }
                    else { } // no subscription found, don't do that!  
                    return list;
                });
        }

        public void UnsubscribeAsk(IStock stock, IMarketUpdateAsk callback)
        {
            _mapAskRequests.AddOrUpdate(stock,
                (security) =>
                {
                    // shouldn't ever really come in here
                    _mapSecuritiesCount.AddOrUpdate(stock,
                        (symbol) =>
                        {
                            return 0;
                        },
                        (symbol, count) =>
                        {
                            return count;
                        });
                    return new List<IMarketUpdateAsk>();
                },
                (security, list) =>
                {
                    if (list.Contains(callback))
                    {
                        _mapSecuritiesCount.AddOrUpdate(stock,
                            (symbol) =>
                            {
                                return 0;
                            },
                            (symbol, count) =>
                            {
                                return --count;
                            });
                        list.Remove(callback);
                    }
                    else { } // no subscription found, don't do that!  
                    return list;
                });
        }

        public void UnsubscribeLast(IStock stock, IMarketUpdateLast callback)
        {
            if (stock is StockSecurity)
            {
                _mapLastRequests.AddOrUpdate(stock,
                    (security) =>
                    {
                        // shouldn't ever really come in here
                        _mapSecuritiesCount.AddOrUpdate(stock,
                            (symbol) =>
                            {
                                return 0;
                            },
                            (symbol, count) =>
                            {
                                return count;
                            });
                        return new List<IMarketUpdateLast>();
                    },
                    (security, list) =>
                    {
                        if (list.Contains(callback))
                        {
                            _mapSecuritiesCount.AddOrUpdate(stock,
                                (symbol) =>
                                {
                                    return 0;
                                },
                                (symbol, count) =>
                                {
                                    return --count;
                                });
                            list.Remove(callback);
                        }
                        else { } // no subscription found, don't do that!  
                        return list;
                    });
            }
            else
            {
                // need to implement listing requests
            }
        }

        public void UnsubscribePhase(IStock stock, IMarketUpdatePhase callback)
        {
            _mapPhaseRequests.AddOrUpdate(stock,
                (security) =>
                {
                    // shouldn't ever really come in here
                    _mapSecuritiesCount.AddOrUpdate(stock,
                        (symbol) =>
                        {
                            return 0;
                        },
                        (symbol, count) =>
                        {
                            return count;
                        });
                    return new List<IMarketUpdatePhase>();
                },
                (security, list) =>
                {
                    if (list.Contains(callback))
                    {
                        _mapSecuritiesCount.AddOrUpdate(stock,
                            (symbol) =>
                            {
                                return 0;
                            },
                            (symbol, count) =>
                            {
                                return --count;
                            });
                        list.Remove(callback);
                    }
                    else { } // no subscription found, don't do that!  
                    return list;
                });
        }




        public void SubscribeOpen(IStock stock, IMarketUpdateOpen callback)
        {
            throw new NotImplementedException();
        }

        public void UnsubscribeOpen(IStock stock, IMarketUpdateOpen callback)
        {
            throw new NotImplementedException();
        }
    }
}
